package cn.jsu.oj.dispatchServer.satellite.server;

import cn.jsu.oj.dispatchServer.satellite.factory.Factory;
import cn.jsu.oj.dispatchServer.satellite.handler.Handler;
import cn.jsu.oj.dispatchServer.satellite.netty.starter.SatelliteStarter;
import cn.jsu.oj.dispatchServer.satellite.pojo.net.AbsPackNet;
import cn.jsu.oj.dispatchServer.satellite.pojo.net.PackNet;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 卫星服务端
 *
 * @author shan
 * @date 2022/07/07
 */
@Slf4j
@Component("satelliteServer")
@DependsOn({"executorService", "handlerFactory"})
public class SatelliteServer implements Client {

    @Autowired
    Factory handlerFactory;

    @Autowired
    ExecutorService executorService;

    private Channel channel;

    private LinkedBlockingQueue<Object> messageQueue;

    private Boolean isClose;

    public SatelliteServer() {
        log.info("----------服务端容器配置完成......");
    }

    public Channel getChannel() {
        return channel;
    }

    @Override
    public void init(Channel channel) {
        this.channel = channel;
        this.isClose = false;
        this.messageQueue = new LinkedBlockingQueue<>(1024);
    }

    @Override
    public void addPack(PackNet<?> packNet) {
        try {
            this.messageQueue.put(packNet);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void close() {
        this.isClose = true;
        this.messageQueue.clear();
        if (this.channel != null) {
            this.channel.close();
        }
        SatelliteStarter.activeSign = false;
        SatelliteStarter.verifySign = false;
    }

    @Override
    public void run() {
        while (!this.isClose) {
            try {
                PackNet<?> packNet = (PackNet<?>) this.messageQueue.take();
                Short typeNo = ((AbsPackNet) packNet.getMessage()).getTypeNo();
                executorService.execute(() -> {
                    try {
                        ((Handler) handlerFactory.getProduct(typeNo)).handle(packNet);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
